package main

import (
	"encoding/json"
	"fmt"
)

type Memento interface {
	GetState() string
}

// 这里存档的封装虽然未暴露set方法和实例对象，但其实仍然可以通过创建新对象添加到存档管理器来进行修改，
// 应该还有别的安全方法协助保证存档安全，但此处不展开了
type GameMemento struct {
	Name string
	HP   int
	MP   int
}

func (g *GameMemento) GetState() string {
	data, _ := json.Marshal(g)
	return string(data)
}

type CareTaker struct {
	Mementos []Memento
}

func (c *CareTaker) AddMemento(memento Memento) {
	c.Mementos = append(c.Mementos, memento)
}

func (c *CareTaker) GetMemento(index int) Memento {
	return c.Mementos[index]
}

type Gamer struct {
	Name string
	HP   int
	MP   int
}

func (g *Gamer) Save() Memento {
	return &GameMemento{
		Name: g.Name,
		HP:   g.HP,
		MP:   g.MP,
	}
}

func (g *Gamer) Load(memento Memento) {
	state := memento.GetState()
	m := &GameMemento{}
	json.Unmarshal([]byte(state), m)
	g.HP = m.HP
	g.MP = m.MP
	g.Name = m.Name
}

func main() {
	g := &Gamer{
		Name: "Player1",
		HP:   100,
		MP:   50,
	}
	ct := &CareTaker{}
	fmt.Println("Current state:", g.HP, g.MP)
	ct.AddMemento(g.Save())
	g.HP -= 20
	fmt.Println("Current state:", g.HP, g.MP)
	ct.AddMemento(g.Save())
	g.MP -= 30
	fmt.Println("Current state:", g.HP, g.MP)
	ct.AddMemento(g.Save())
	g.Load(ct.GetMemento(1))
	fmt.Println("After load:", g.HP, g.MP)
	g.Load(ct.GetMemento(0))
	fmt.Println("After load:", g.HP, g.MP)
}
